package com.sujeet.learning.xml;

import java.awt.BorderLayout;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

public class SAXTreeViewer extends JFrame {
	/** Default parser to use */
	private String vendorParserClass = "org.apache.xerces.parsers.SAXParser";
	/** The base tree to render */
	private JTree jTree;
	/** Tree model to use */
	DefaultTreeModel defaultTreeModel;

	public SAXTreeViewer() {
		// Handle Swing setup
		super("SAX Tree Viewer");
		setSize(600, 450);
	}

	public void init(String xmlURI) throws IOException, SAXException {
		DefaultMutableTreeNode base = new DefaultMutableTreeNode(
				"XML Document: " + xmlURI);
		// Build the tree model
		defaultTreeModel = new DefaultTreeModel(base);
		jTree = new JTree(defaultTreeModel);
		// Construct the tree hierarchy
		buildTree(defaultTreeModel, base, xmlURI);

		// Display the results
		getContentPane().add(new JScrollPane(jTree), BorderLayout.CENTER);
	}

	public void buildTree(DefaultTreeModel treeModel,
			DefaultMutableTreeNode base, String xmlURI) throws IOException,
			SAXException {
		// Create instances needed for parsing
		XMLReader reader = XMLReaderFactory.createXMLReader(vendorParserClass);
		// Register content handler
		ContentHandler jTreeContentHandler =
				new JTreeContentHandler(treeModel, base);

		// Register error handler
		reader.setContentHandler(jTreeContentHandler);
		reader.setFeature("http://xml.org/sax/features/validation", true);
		// Parse
		java.io.File f = new java.io.File(xmlURI);
		System.out.println(f.canRead());
		InputSource inputSource = new InputSource(xmlURI);
		reader.parse(inputSource);

	}

	public static void main(String[] args) {
		try {
			// if (args.length != 1) {
			// System.out.println("Usage: java javaxml2.SAXTreeViewer "
			// + "[XML Document URI]");
			// System.exit(0);
			// }
			SAXTreeViewer viewer = new SAXTreeViewer();
			viewer.init("src/main/resources/com/sujeet/learning/xml/contents.xml");
			viewer.setVisible(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	class JTreeContentHandler implements ContentHandler {
		/** Tree Model to add nodes to */
		private DefaultTreeModel treeModel;
		/** Current node to add sub-nodes to */
		private DefaultMutableTreeNode current;
		/** Hold onto the locator for location information */
		private Locator locator;
		/** Store URI to prefix mappings */
		private Map namespaceMappings;

		public JTreeContentHandler(DefaultTreeModel treeModel,
				DefaultMutableTreeNode base) {
			this.treeModel = treeModel;
			this.current = base;
			this.namespaceMappings = new HashMap();

		}

		// ContentHandler method implementations
		public void setDocumentLocator(Locator locator) {
			// Save this for later use
			this.locator = locator;
		}

		public void startDocument() throws SAXException {
			// No visual events occur here
			System.out.println("Start parsing");
		}

		public void endDocument() throws SAXException {
			// No visual events occur here
			System.out.println("End parsing");

		}

		public void processingInstruction(String target, String data)
				throws SAXException {

			DefaultMutableTreeNode pi = new DefaultMutableTreeNode(
					"PI (target = '" + target + "', data = '" + data + "')");
			current.add(pi);
		}

		public void startPrefixMapping(String prefix, String uri) {
			// No visual events occur here.
			namespaceMappings.put(uri, prefix);
			System.out.println("Found namespace mapping start: prefix="+prefix+" uri="+uri);
		}
		
		public void ignorableWhitespace(char[] ch, int start, int length)
				throws SAXException {
				}
				// This is ignorable, so don't display it

		public void endPrefixMapping(String prefix) {
			// No visual events occur here.
			System.out.println("Found namespace mapping end: prefix="+prefix);
			for (Iterator i = namespaceMappings.keySet().iterator(); i
					.hasNext();) {

				String uri = (String) i.next();
				String thisPrefix = (String) namespaceMappings.get(uri);
				if (prefix.equals(thisPrefix)) {
					namespaceMappings.remove(uri);
					break;
				}
			}
		}

		public void startElement(String namespaceURI, String localName,
				String qName, Attributes atts) throws SAXException {
			System.out.println("Event: startElement");
			System.out.println("Found element name: "+localName);
			System.out.println("Found element qualifiedName: "+qName);
			DefaultMutableTreeNode element = new DefaultMutableTreeNode(
					"Element: " + localName);
			current.add(element);
			current = element;
			// Determine namespace
			if (namespaceURI.length() > 0) {
				String prefix = (String) namespaceMappings.get(namespaceURI);
				if (prefix.equals("")) {
					prefix = "[None]";
				}
				DefaultMutableTreeNode namespace = new DefaultMutableTreeNode(
						"Namespace: prefix = '" + prefix + "', URI = '"
								+ namespaceURI + "'");
				current.add(namespace);
			}

			// Process attributes
			for (int i = 0; i < atts.getLength(); i++) {
				System.out.println("attribute #" + i + atts.getLocalName(i));
				DefaultMutableTreeNode attribute = new DefaultMutableTreeNode(
						"Attribute (name = '" + atts.getLocalName(i)
								+ "', value = '" + atts.getValue(i) + "')");
				String attURI = atts.getURI(i);
				if (attURI.length() > 0) {
					String attPrefix = (String) namespaceMappings
							.get(namespaceURI);
					if (attPrefix.equals("")) {
						attPrefix = "[None]";
					}
					DefaultMutableTreeNode attNamespace = new DefaultMutableTreeNode(
							"Namespace: prefix = '" + attPrefix + "', URI = '"
									+ attURI + "'");
					attribute.add(attNamespace);
				}
				current.add(attribute);
			}

		}

		public void endElement(String namespaceURI, String localName,
				String qName) throws SAXException {
			// Walk back up the treec
			System.out.println("Event: endElement "+ qName);
		}
		
		public void characters(char[] ch, int start, int length)
				throws SAXException {
				System.out.println("Event: startCharacters");
				String s = new String(ch, start, length);
				DefaultMutableTreeNode data =
				new DefaultMutableTreeNode("Character Data: '" + s + "'");
				current.add(data);
		}
		
		public void skippedEntity(String name) throws SAXException {
			System.out.println("Event: skipped Entity");
			System.out.println("skippedEntity name: "+ name);
			DefaultMutableTreeNode skipped =
			new DefaultMutableTreeNode("Skipped Entity: '" + name + "'");
			current.add(skipped);
			}

	}

}
